﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Galaxy
{
	public enum GalaxyBaseType //顺序必须和TClass.h中的类型声明顺序一样
    {
        Error = -1,
        Bool = 0,
        UInt8,
        Int8,
        UInt16,
        Int16,
        UInt32,
        Int32,
        UInt64,
        Int64,        
        F32,
        F64,
        String,
        Class,
    }
	
    public class GalaxyTypeConvert
    {
        protected static Dictionary<string, GalaxyBaseType> mTypeMap = new Dictionary<string, GalaxyBaseType>();
        static bool IsInit = false;
        public static string Type2String(GalaxyBaseType type)
        {
            switch (type)
            {
                case GalaxyBaseType.Int8:
                    {
                        return "int8";
                    }
                case GalaxyBaseType.Int16:
                    {
                        return "int16";
                    }
                case GalaxyBaseType.Int32:
                    {
                        return "int32";
                    }
                case GalaxyBaseType.UInt8:
                    {
                        return "uint8";
                    }
                case GalaxyBaseType.UInt16:
                    {
                        return "uint16";
                    }
                case GalaxyBaseType.UInt32:
                    {
                        return "uint32";
                    }
                case GalaxyBaseType.Int64:
                    {
                        return "int64";
                    }
                case GalaxyBaseType.UInt64:
                    {
                        return "uint64";
                    }
                case GalaxyBaseType.F32:
                    {
                        return "f32";
                    }
                case GalaxyBaseType.F64:
                    {
                        return "f64";
                    }
                case GalaxyBaseType.String:
                    {
                        return "char";
                    }
                case GalaxyBaseType.Bool:
                    {
                        return "bool";
                    }
            }
            return "int32";
        }
        public static GalaxyBaseType String2Type(string str)
        {
            if(!IsInit)
            {
                IsInit = true;
                mTypeMap["int8"] = GalaxyBaseType.Int8;
                mTypeMap["bool"] = GalaxyBaseType.Bool;
                mTypeMap["uint8"] = GalaxyBaseType.UInt8;
                mTypeMap["uint16"] = GalaxyBaseType.UInt16;
                mTypeMap["int16"] = GalaxyBaseType.Int16;
                mTypeMap["uint32"] = GalaxyBaseType.UInt32;
                mTypeMap["int32"] = GalaxyBaseType.Int32;
                mTypeMap["uint64"] = GalaxyBaseType.UInt64;
                mTypeMap["int64"] = GalaxyBaseType.Int64;      
                mTypeMap["f32"] = GalaxyBaseType.F32;
                mTypeMap["f64"] = GalaxyBaseType.F64;
                mTypeMap["char"] = GalaxyBaseType.String;
                mTypeMap["class"] = GalaxyBaseType.Class;
            }
            if(!mTypeMap.ContainsKey(str))
            {
                return GalaxyBaseType.Error;
            }
            return mTypeMap[str];
        }
    }

    public class ParamBase
    {
        public ParamBase()
        {
            mOffset = 0;
            mSize = 4;
        }
        public GalaxyBaseType mParamType = GalaxyBaseType.Int32;
        public string mParamName;
        public int mSize;
        public int mIndex;
        public int mOffset;

        public virtual bool PacketRead(byte[] src, ref int pktbuffOff, byte[] tar)
        {
            if(mParamType == GalaxyBaseType.String)
            {
                if (pktbuffOff+2 >= src.Length)
                {
                    return false;
                }
                mSize = (int)GalaxyBitConverter.ToInt16(src, pktbuffOff);
                if (mSize < 0 || pktbuffOff + 2 + mSize > src.Length)
                    return false;
                pktbuffOff += 2;
            }
            if (pktbuffOff + mSize > src.Length || mOffset + mSize > tar.Length)
                return false;
            bool bChange = false;
            for (int i = 0; i < mSize; ++i)
            {
                if (src[i+ pktbuffOff] != tar[ i + mOffset])
                {
                    bChange = true;
                    break;
                }
            }
            Buffer.BlockCopy(src, pktbuffOff, tar, mOffset, mSize);
            pktbuffOff += mSize;
            return bChange;
        }
        public bool GetBool(ref byte[] st)
        {
            return GalaxyBitConverter.ToBoolean(st, mOffset);
        }
        public sbyte GetSByte(ref byte[] st)
        {
            return (sbyte)st[mOffset];
        }
        public byte GetByte(ref byte[] st)
        {
            return st[mOffset];
        }
        public short GetInt16(ref byte[] st)
        {
            return GalaxyBitConverter.ToInt16(st, mOffset);
        }
        public ushort GetUInt16(ref byte[] st)
        {
            return GalaxyBitConverter.ToUInt16(st, mOffset);
        }
        public int GetInt32(ref byte[] st)
        {
            return GalaxyBitConverter.ToInt32(st, mOffset);
        }
        public uint GetUInt32(ref byte[] st)
        {
            return GalaxyBitConverter.ToUInt32(st, mOffset);
        }
        public long GetInt64(ref byte[] st)
        {
            return GalaxyBitConverter.ToInt64(st, mOffset);
        }
        public ulong GetUInt64(ref byte[] st)
        {
            return GalaxyBitConverter.ToUInt64(st, mOffset);
        }
        public float GetFloat(ref byte[] st)
        {
            return GalaxyBitConverter.ToSingle(st, mOffset);
        }
        public double GetDouble(ref byte[] st)
        {
            return GalaxyBitConverter.ToDouble(st, mOffset);
        }
        public string GetString(ref byte[] st)
        {
            if (mSize<0 || mSize >= st.Length - mOffset)
            {
                return null;
            }
            int tempSize = mSize;
            for(int i = 0; i<mSize; i++)
            {
                int index = mOffset + i;
                if (st[index] == '\0')
                {
                    tempSize = i;
                    break;
                }
            }
            return System.Text.Encoding.Default.GetString(st, mOffset, tempSize);
        }

        static byte[] s_GetStringBuffer = null;

        public string GetString_UTF8(ref byte[] st)
        {
            if (mSize < 0 || mSize >= st.Length - mOffset)
            {
                return null;
            }
            int tempSize = mSize;
            for (int i = 0; i < mSize; i++)
            {
                int index = mOffset + i;
                if (st[index] == '\0')
                {
                    tempSize = i;
                    break;
                }
            }
            return System.Text.Encoding.UTF8.GetString(st, mOffset, tempSize);
        }
        public string GetString_UTF8_old(ref byte[] st)
        {
            return GetString(ref st);
            try
            {
                string strAscii = Encoding.Default.GetString(st, mOffset, mSize);
                ////gb2312   
                //System.Text.Encoding gb2312 = System.Text.Encoding.GetEncoding("gb2312");
                ////utf8   
                //System.Text.Encoding utf8 = System.Text.Encoding.GetEncoding("utf-8");
                //byte[] gb;
                //gb = gb2312.GetBytes(strAscii);
                //gb = System.Text.Encoding.Convert(gb2312, utf8, gb);
                ////返回转换后的字符   
                //return utf8.GetString(gb);

                //将ASCII字符转换为汉字
                string textStr = string.Empty;
                int k = 0;//字节移动偏移量
                int j = 0;
                if (s_GetStringBuffer == null || s_GetStringBuffer.Length < strAscii.Length / 2)
                {
                    s_GetStringBuffer = new byte[strAscii.Length / 2];
                }
                Array.Clear(s_GetStringBuffer, 0, s_GetStringBuffer.Length);
                //byte[] buffer = new byte[strAscii.Length / 2];//存储变量的字节
                for (; j < strAscii.Length / 2; ++j)
                {
                    if (strAscii[k] == '\0')
                        break;
                    byte localbyte = 0;
                    //每两位合并成为一个字节
                    if (!byte.TryParse(strAscii.Substring(k, 2), System.Globalization.NumberStyles.HexNumber, null, out localbyte))
                    {
                        break;
                    }
                    s_GetStringBuffer[j] = localbyte;
                    k = k + 2;
                }
                if (s_GetStringBuffer[0] == '\0')
                {
                    return "";
                }
                return Encoding.Default.GetString(s_GetStringBuffer, 0, j);
                //return Encoding.Unicode.GetString(st, mOffset, mSize);
            }
            catch (System.Exception ex)
            {
                return "";
            }
           
        }

        public object GetValue(ref byte[] st)
        {
            switch(mParamType)
            {
                case GalaxyBaseType.Bool:
                    return GetBool(ref st);
                case GalaxyBaseType.Int8:
                    return GetByte(ref st);
                case GalaxyBaseType.UInt8:
                    return GetSByte(ref st);
                case GalaxyBaseType.Int16:
                    return GetInt16(ref st);
                case GalaxyBaseType.UInt16:
                    return GetUInt16(ref st);
                case GalaxyBaseType.Int32:
                    return GetInt32(ref st);
                case GalaxyBaseType.UInt32:
                    return GetUInt32(ref st);
                case GalaxyBaseType.Int64:
                    return GetInt64(ref st);
                case GalaxyBaseType.UInt64:
                    return GetUInt64(ref st);
                case GalaxyBaseType.F32:
                    return GetFloat(ref st);
                case GalaxyBaseType.F64:
                    return GetDouble(ref st);
                case GalaxyBaseType.String:
                    return GetString(ref st);
            }
            return null;
        }

        public void SetSByte(ref byte[] st, sbyte val)
        {
            st[mOffset] = (byte)val;
        }
        public void SetByte(ref byte[] st, byte val)
        {
            st[mOffset] = val;
        }
        public void SetBool(ref byte[] st, bool val)
        {
            GalaxyBitConverter.WriteBytesBool(st, mOffset, val);
        }
        public void SetInt16(ref byte[] st, short val)
        {
            GalaxyBitConverter.WriteBytesInt16(st, mOffset, val);
        }
        public void SetUInt16(ref byte[] st, ushort val)
        {
            GalaxyBitConverter.WriteBytesUInt16(st, mOffset, val);
        }
        public void SetInt32(ref byte[] st, int val)
        {
            GalaxyBitConverter.WriteBytesInt32(st, mOffset, val);
        }
        public void SetUInt32(ref byte[] st, uint val)
        {
            GalaxyBitConverter.WriteBytesUInt32(st, mOffset, val);
        }
        public void SetInt64(ref byte[] st, long val)
        {
            GalaxyBitConverter.WriteBytesInt64(st, mOffset, val);
        }
        public void SetUInt64(ref byte[] st, ulong val)
        {
            GalaxyBitConverter.WriteBytesUInt64(st, mOffset, val);
        }
        public void SetFloat(ref byte[] st, float val)
        {
            GalaxyBitConverter.WriteBytesSingle(st, mOffset, val);
        }
        public void SetDouble(ref byte[] st, double val)
        {
            GalaxyBitConverter.WriteBytesDouble(st, mOffset, val);
        }
        public void SetString(ref byte[] st, string val)
        {
            byte[] str = System.Text.Encoding.Default.GetBytes(val);
            int size = str.Length;
            if (size > mSize)
                size = mSize;
            Buffer.BlockCopy(str, 0, st, mOffset, size);
            
        }        
    }
}
